{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f32276ae-b51f-4778-8405-1da83927d2a8",
   "metadata": {},
   "source": [
    "# A graphical example\n",
    "\n",
    "We'll cover building a basic model and plotting the decision boundary used from previous chapters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5439e1cb-9621-444d-acb1-90ff3d34107b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Imports\n",
    "\n",
    "import pandas\n",
    "import numpy\n",
    "import matplotlib.pyplot as plt\n",
    "import tensorflow\n",
    "import tensorflow.keras\n",
    "from tensorflow.keras.models import Sequential\n",
    "from tensorflow.keras.layers import Dense, Dropout, Activation\n",
    "from tensorflow.keras.optimizers import SGD\n",
    "\n",
    "import _plotting\n",
    "\n",
    "# Setting random seeds to get reproducible results\n",
    "numpy.random.seed(0)\n",
    "tensorflow.random.set_seed(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "31f992b5-3c61-4fe7-9678-5aa1871bd237",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Read the dataset\n",
    "data = pandas.read_csv('one_circle.csv', index_col=0)\n",
    "columns_features = ['x_1', 'x_2']\n",
    "column_label = 'y'\n",
    "features = data[columns_features].values\n",
    "labels = data[column_label].values\n",
    "\n",
    "_plotting.plot_scatter(data['x_1'][labels == 0], data['x_2'][labels == 0], marker = 's')\n",
    "_plotting.plot_scatter(data['x_1'][labels == 1], data['x_2'][labels == 1], marker = '^')\n",
    "plt.xlabel('x_1')\n",
    "plt.ylabel('x_2')\n",
    "plt.legend([\"Happy\", \"Sad\"])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e35a55ab-a410-4825-9870-030e44967405",
   "metadata": {},
   "source": [
    "## Preprocessing\n",
    "We'll convert the label column to categorical to make it easier for the model to process. It also saves memory too.\n",
    "Pandas has a built-in function called factorize, which interprets the number of classes for us.\n",
    "Unlike keras.utils.to_categorical, this returns a 1D-array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a96d1026-2a2a-434f-ad39-9f8430a33051",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Categorizing the output\n",
    "series_labels, labels = pandas.factorize(data[column_label])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d675cbeb-62d5-42ad-a347-c5a704d8e682",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
       "        0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,\n",
       "        0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0,\n",
       "        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,\n",
       "        1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0],\n",
       "       dtype=int64),\n",
       " Int64Index([0, 1], dtype='int64'))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series_labels, labels"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa8058ac-1da6-46af-81bd-9f76deabb8fe",
   "metadata": {},
   "source": [
    "## Model Structure\n",
    "\n",
    "We'll use a sequential model to add a few dense layers with the ReLu activation function. Why are we using sigmoid instead of softmax? It's also a common practice to add dropout. It is also a good idea to set our unit sizes as powers of 2, which was a trick for training slightly faster on GPUs. . We also use sparse_categorical_crossentropy since our labels are 1D."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a633e485-6a3e-4efb-b4c9-76c72900f8b0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      " Layer (type)                Output Shape              Param #   \n",
      "=================================================================\n",
      " dense (Dense)               (None, 128)               384       \n",
      "                                                                 \n",
      " dropout (Dropout)           (None, 128)               0         \n",
      "                                                                 \n",
      " dense_1 (Dense)             (None, 64)                8256      \n",
      "                                                                 \n",
      " dropout_1 (Dropout)         (None, 64)                0         \n",
      "                                                                 \n",
      " dense_2 (Dense)             (None, 2)                 130       \n",
      "                                                                 \n",
      "=================================================================\n",
      "Total params: 8,770\n",
      "Trainable params: 8,770\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "# Building the model\n",
    "num_units_penultimate = 2**6\n",
    "model = Sequential()\n",
    "model.add(Dense(2**7, activation='relu', input_shape=(features.shape[1],)))\n",
    "model.add(Dropout(.2))\n",
    "model.add(Dense(num_units_penultimate, activation='relu'))\n",
    "model.add(Dropout(.2))\n",
    "model.add(Dense(len(labels), activation='sigmoid')) # two classes, else softmax\n",
    "\n",
    "# Compiling the model\n",
    "model.compile(\n",
    "    loss = 'sparse_categorical_crossentropy', # 1D labels, else categorical_crossentropy\n",
    "    optimizer='adam', \n",
    "    metrics=['accuracy']\n",
    ")\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab155374-6527-4d87-85e0-a33cb4be83d7",
   "metadata": {},
   "source": [
    "## Training the Model\n",
    "It's a good practice to set your batch size equal to the number of penultimate neurons in your layer. Training accuracy will vary due to the stochastic nature of the model, but you can clearly see the loss going down and the accuracy going up."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "23931e74-ca35-4f2e-b0b4-a91cf2d9f479",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/100\n",
      "2/2 [==============================] - 1s 5ms/step - loss: 0.6353 - accuracy: 0.6727\n",
      "Epoch 2/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.5599 - accuracy: 0.7364\n",
      "Epoch 3/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.5048 - accuracy: 0.7636\n",
      "Epoch 4/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4643 - accuracy: 0.7636\n",
      "Epoch 5/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4711 - accuracy: 0.7636\n",
      "Epoch 6/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4485 - accuracy: 0.7636\n",
      "Epoch 7/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4415 - accuracy: 0.7636\n",
      "Epoch 8/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4531 - accuracy: 0.7636\n",
      "Epoch 9/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4667 - accuracy: 0.7636\n",
      "Epoch 10/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4532 - accuracy: 0.7636\n",
      "Epoch 11/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4372 - accuracy: 0.7636\n",
      "Epoch 12/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4614 - accuracy: 0.7636\n",
      "Epoch 13/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4456 - accuracy: 0.7636\n",
      "Epoch 14/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4272 - accuracy: 0.7636\n",
      "Epoch 15/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4234 - accuracy: 0.7636\n",
      "Epoch 16/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4367 - accuracy: 0.7636\n",
      "Epoch 17/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4437 - accuracy: 0.7636\n",
      "Epoch 18/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4215 - accuracy: 0.7636\n",
      "Epoch 19/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4383 - accuracy: 0.7636\n",
      "Epoch 20/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4315 - accuracy: 0.7636\n",
      "Epoch 21/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4327 - accuracy: 0.7636\n",
      "Epoch 22/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4443 - accuracy: 0.7636\n",
      "Epoch 23/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4247 - accuracy: 0.7636\n",
      "Epoch 24/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4308 - accuracy: 0.7636\n",
      "Epoch 25/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4346 - accuracy: 0.7636\n",
      "Epoch 26/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3979 - accuracy: 0.7636\n",
      "Epoch 27/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4168 - accuracy: 0.7636\n",
      "Epoch 28/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4175 - accuracy: 0.7636\n",
      "Epoch 29/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4219 - accuracy: 0.7636\n",
      "Epoch 30/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4317 - accuracy: 0.7636\n",
      "Epoch 31/100\n",
      "2/2 [==============================] - 0s 6ms/step - loss: 0.4147 - accuracy: 0.7636\n",
      "Epoch 32/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4238 - accuracy: 0.7636\n",
      "Epoch 33/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4070 - accuracy: 0.7636\n",
      "Epoch 34/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3987 - accuracy: 0.7636\n",
      "Epoch 35/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4030 - accuracy: 0.7636\n",
      "Epoch 36/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3987 - accuracy: 0.7636\n",
      "Epoch 37/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3996 - accuracy: 0.7636\n",
      "Epoch 38/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4098 - accuracy: 0.7636\n",
      "Epoch 39/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4255 - accuracy: 0.7636\n",
      "Epoch 40/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3968 - accuracy: 0.7636\n",
      "Epoch 41/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3902 - accuracy: 0.7636\n",
      "Epoch 42/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.4079 - accuracy: 0.7636\n",
      "Epoch 43/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3863 - accuracy: 0.7818\n",
      "Epoch 44/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.4085 - accuracy: 0.7727\n",
      "Epoch 45/100\n",
      "2/2 [==============================] - 0s 6ms/step - loss: 0.4035 - accuracy: 0.7727\n",
      "Epoch 46/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3837 - accuracy: 0.7818\n",
      "Epoch 47/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3844 - accuracy: 0.7727\n",
      "Epoch 48/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3847 - accuracy: 0.7909\n",
      "Epoch 49/100\n",
      "2/2 [==============================] - 0s 18ms/step - loss: 0.3852 - accuracy: 0.7909\n",
      "Epoch 50/100\n",
      "2/2 [==============================] - 0s 11ms/step - loss: 0.3775 - accuracy: 0.8000\n",
      "Epoch 51/100\n",
      "2/2 [==============================] - 0s 15ms/step - loss: 0.3724 - accuracy: 0.7909\n",
      "Epoch 52/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3805 - accuracy: 0.8000\n",
      "Epoch 53/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3689 - accuracy: 0.7909\n",
      "Epoch 54/100\n",
      "2/2 [==============================] - 0s 3ms/step - loss: 0.3665 - accuracy: 0.7909\n",
      "Epoch 55/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3833 - accuracy: 0.7909\n",
      "Epoch 56/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3594 - accuracy: 0.7909\n",
      "Epoch 57/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3724 - accuracy: 0.7909\n",
      "Epoch 58/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3725 - accuracy: 0.8000\n",
      "Epoch 59/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3853 - accuracy: 0.8000\n",
      "Epoch 60/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3907 - accuracy: 0.8091\n",
      "Epoch 61/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3694 - accuracy: 0.8091\n",
      "Epoch 62/100\n",
      "2/2 [==============================] - 0s 3ms/step - loss: 0.3712 - accuracy: 0.8000\n",
      "Epoch 63/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3653 - accuracy: 0.8091\n",
      "Epoch 64/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3560 - accuracy: 0.8091\n",
      "Epoch 65/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3520 - accuracy: 0.8091\n",
      "Epoch 66/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3667 - accuracy: 0.8182\n",
      "Epoch 67/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3691 - accuracy: 0.8182\n",
      "Epoch 68/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3448 - accuracy: 0.8273\n",
      "Epoch 69/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3562 - accuracy: 0.8273\n",
      "Epoch 70/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3534 - accuracy: 0.8273\n",
      "Epoch 71/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3663 - accuracy: 0.8273\n",
      "Epoch 72/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3442 - accuracy: 0.8273\n",
      "Epoch 73/100\n",
      "2/2 [==============================] - 0s 3ms/step - loss: 0.3456 - accuracy: 0.8091\n",
      "Epoch 74/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3433 - accuracy: 0.8364\n",
      "Epoch 75/100\n",
      "2/2 [==============================] - 0s 3ms/step - loss: 0.3412 - accuracy: 0.8455\n",
      "Epoch 76/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3354 - accuracy: 0.8455\n",
      "Epoch 77/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3552 - accuracy: 0.8182\n",
      "Epoch 78/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3225 - accuracy: 0.8545\n",
      "Epoch 79/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3322 - accuracy: 0.8455\n",
      "Epoch 80/100\n",
      "2/2 [==============================] - 0s 3ms/step - loss: 0.3366 - accuracy: 0.8455\n",
      "Epoch 81/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3389 - accuracy: 0.8545\n",
      "Epoch 82/100\n",
      "2/2 [==============================] - 0s 3ms/step - loss: 0.3256 - accuracy: 0.8909\n",
      "Epoch 83/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3288 - accuracy: 0.8727\n",
      "Epoch 84/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3328 - accuracy: 0.8455\n",
      "Epoch 85/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3289 - accuracy: 0.8455\n",
      "Epoch 86/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3117 - accuracy: 0.8727\n",
      "Epoch 87/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3117 - accuracy: 0.8909\n",
      "Epoch 88/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3162 - accuracy: 0.8727\n",
      "Epoch 89/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3145 - accuracy: 0.8727\n",
      "Epoch 90/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3275 - accuracy: 0.8909\n",
      "Epoch 91/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3354 - accuracy: 0.8455\n",
      "Epoch 92/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3062 - accuracy: 0.8727\n",
      "Epoch 93/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3086 - accuracy: 0.8818\n",
      "Epoch 94/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3023 - accuracy: 0.9091\n",
      "Epoch 95/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.2964 - accuracy: 0.9091\n",
      "Epoch 96/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3223 - accuracy: 0.8818\n",
      "Epoch 97/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3084 - accuracy: 0.8818\n",
      "Epoch 98/100\n",
      "2/2 [==============================] - 0s 6ms/step - loss: 0.3555 - accuracy: 0.8636\n",
      "Epoch 99/100\n",
      "2/2 [==============================] - 0s 5ms/step - loss: 0.3013 - accuracy: 0.8818\n",
      "Epoch 100/100\n",
      "2/2 [==============================] - 0s 4ms/step - loss: 0.3239 - accuracy: 0.8727\n"
     ]
    }
   ],
   "source": [
    "# Training the model\n",
    "history = model.fit(features, series_labels, epochs=100, batch_size=num_units_penultimate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "4f28374e-3a91-41d1-a0b4-f6cad3495a88",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "198/198 [==============================] - 0s 2ms/step\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWgAAAD8CAYAAABaZT40AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAkzElEQVR4nO3de5RcZZnv8e/TnQ5NQguBIEaIBDEqFyGRDJw5eBo0ghkPkBFGCEwSQDhZLMgx422UQRKJgwMzSobR4NiLBLlJEgUxMDgQI5hRAdPRIEkwGqKBREYOuTTE3PrynD9qV6hU17121d5V+/dZqxe9d+3a+6VS9fRbz37e9zV3R0RE4qcl6gaIiEhuCtAiIjGlAC0iElMK0CIiMaUALSISUwrQIiIxpQAtIlIGM1toZq+a2Zo8j5uZ/ZuZbTCzX5vZ+zMe6zez1cHP0mLXUoAWESnPt4FJBR7/K2Bs8DMD+GbGY7vdfVzwc0GxCylAi4iUwd1XANsKHDIZuMdTngEOM7NRlVxrSCVPqlZHS6sf0dIWxaVFpMFs6t/7mrsfWc052ked5AN7dxY9rnf7S2uBPRm7uty9q8zLHQ28nLG9Odj3CtBuZt1AH3CLuz9c6ESRBOgjWtq48S1jori0iDSYq7ev31TtOQb27mTkOV8oetwrS67d4+4Tqr1eAce6+xYzeyfwYzN73t1fzHewUhwiIuHaAozO2D4m2Ie7p/+7EXgKGF/oRArQIiLhWgpMD6o5/gfQ4+6vmNkIMzsIwMxGAmcC6wqdKJIUh4hIozKzB4CzgZFmthmYA7QBuPu/A48BHwU2ALuAK4OnngB8y8wGSHWOb3F3BWgRkbC4+6VFHnfguhz7fw68r5xrKcUhIhJTCtAiIjGlAC0iElMK0CIiMaUALSISUwrQIiIxpQAtIhJTCtAiIjGlAC0iElMK0CIiMaUALSISUwrQIiIxpQAtIhJTCtAiIjGlAC0iElMK0CIiMVV1gDazdjP7hZk9Z2ZrzeymMBomIpJ0Yayoshf4kLvvNLM24Kdm9kN3fyaEc0uWmT0b2TPQO2h/e0sb3zj0nRG0KB70ukgzqjpAB8u77Aw224Ifr/a8ktuegV6O/fyjg/ZvuvW8CFoTH3pdpBmFsiahmbUCq4B3AfPd/dkwztss1LsTkUqEEqDdvR8YZ2aHAd83s5PdfU3mMWY2A5gBcHhLstaqVe9ORCoRahWHu+8AngQm5Xisy90nuPuEDmsN87IiIk2p6q6smR0J9Lr7DjM7GDgHuLXqlolI2ZROqz0zmwTcDrQCd7r7LVmPHwssBI4EtgFT3X1z8NjlwBeDQ//R3e8udK0wcg2jgLuDPHQLsMTdB3+fl1C0t7TlTI20t7SxY6CP2/78Ep8Z/g4OrTKN1Ggf9EKvS5IonVZbQZybT6ojuhlYaWZL3X1dxmFfBe5x97vN7EPAPwHTzOxwYA4wgVQhxargudvzXS+MKo5fA+OrPY8cqFCAvHPEe3I+57t7/8Su1j6e6N3Kxw86qqrrN9oHPY5/NKQpnQ5scPeNAGa2CJgMZAboE4FPB78/CTwc/P4RYJm7bwueu4xUOviBfBdL1t26KlXaq6ykd1dugNwx0MfTvT08deUwPnhXD+e2HVF1L1qkWQzrGMZpE8cVPe7RJYw0s+6MXV3u3pWxfTTwcsb2ZuCMrNM8B1xIKg3yMaDDzI7I89yjC7VHn2BKD7yV9irr0btb1ruVy09tY/yoVqaf2sYT66rvRYsk0GvuPqHKc3wW+IaZXQGsALYA/ZWcSAGaxvs6ny3de76rczgA13cO5YTn1ItuBo12LyABtgCjM7aPCfbt5+5/JNWDxswOAS4Kiii2AGdnPfepQhfTp7cJpHvPozpSVZOjOlrUi24S5XYedLO05lYCY83sOFKBeQpwWeYBZjYS2ObuA8D1pCo6AB4HvmJmI4Ltc4PH81KAroF693pW79vJ4919fL173wH7jxoyUHGA1ge9MalXXVvu3mdmM0kF21ZgobuvNbO5QLe7LyXVS/4nM3NSKY7rguduM7MvkwryAHPTNwzzUYCugVBSJi2tuY9vGTzI5+aO48tpXkn0QRfJzd0fAx7L2jc74/fvAd/L89yFvNmjLkoBugx17VUO9Dd0XlxEqqcATemBV71KEaknBWgUeCW+dC8g2RSgQ5J9YzD9oWppP4TRsxaVf8IyctDSvMrpPKgkr/koQIek0I3BdKAtq9ejHLSUqdHr+WUwBeg6yDd3hpRPvURJEgVoaSjqJUqShDphv4iIhEcBWkQkppTiCEnY5VAqr5Jy6T3TfBSgQxL2DapC5wtz5RRpHrpJ2nz06W5Ay3q3hrZySqNRL1GSRAG6wSR95RT1EiVJqr5JaGajzexJM1tnZmvNbFYYDZPcBq2c0rs16iaJSI2E0fXqAz7j7r80sw5SK9Uuy1rlVkLQiCunaGCJSOXCWNX7FeCV4Pc3zOwFUgshKkCHrBFXTtHAEpHKhdrtMrMxwHjg2RyPzQBmABwecW+vUXt1tVg5RSpTznuoUd9vEr3QImWwOOKDwN+5++vZjwdLl3cBjBnS7mFdtxKN2qurxcopUply3kON+n6T6IUSoM2sjVRwvt/dHwrjnI0sih5Tva4Z9nXUuxTJr+oAbWYGLABecPfbqm9S44uix1Sva4Z9HfUuRfILowd9JjANeN7MVgf7/iFYWFESTgNLRCoXRhXHTwELoS3ShJSmCJ/SQskRz+LZGlOvTqpVznso7Peb0kLRMrNJwO1AK3Cnu9+S9fg84IPB5jDgre5+WPBYP/B88NhL7n5BoWslMkDHpZehnlDjKuffR/+WzcPMWoH5wDnAZmClmS3NHJjn7p/KOP7/kio9Ttvt7uNKvV4iA3StldpjCrMnFEYvbdojc4se86lJn9C0qpJkpwMb3H0jgJktAiaTf2DepcCcSi+mAF0DUfSYqrlm5yUnc+zUi1l+xFlccNpY+na9MeiYIcM6mDTvcc762rL9+5ZMH8/mT01lxeI1FV9bvUuphyM7hnJtZ/H32qMw0sy6M3Z1BWM40o4GXs7Y3gycketcZnYscBzw44zd7cH5+4Bb3P3hQu1RgE64zktO5ph593HRPb9i1fKH6Nv1Rt5e/arlqw/YdzGwZN59dFJdkJbaKiWVpnTbfq+5+4SQzjUF+J6792fsO9bdt5jZO4Efm9nz7v5ivhMoQDe5dAAu5OJ7fjUo+JZi1fLVHL98NQtums9l8w4t+XnV9rqTrty0UCmpNN14LNkWYHTG9jHBvlymANdl7nD3LcF/N5rZU6Ty0wrQSTTtkbksP+IsPn3Pr/IeU0lgznbVnIc4beK4ko9Xr7s6CevRxs1KYKyZHUcqME8BLss+yMzeC4wAns7YNwLY5e57zWwkqTEk/1zoYgrQEarlDbJ0cL5qTn1G3pcT6C8Grp01n2lTf8Km+5bs36+ALXHn7n1mNhN4nFSZ3UJ3X2tmc4Fud18aHDoFWOTumfMOnQB8y8wGSM3Ff0uxaZkVoCNUi55Qdk45jlYtX81Vy1ez4KYLOXvem2Wgl81T+kPiLxgl/VjWvtlZ21/K8byfA+8r51oK0E0kHZwrzSkD2NBhOXv1NnRYla0bLLt3f9rEcUp/iGRQgG4ix069mOV/6Kkqr/y2v/5qeA0qU+ZNx2lTf5L3uE33LUl8AC+n6qKUVJrq0eNJAVpi56o5D7HgpgvzHzDrLKZN/Qn3nj87/zFNrpyqi1JSabrxGE8K0BK6/t09vP6Tr/GWsz5D68Gll99lKnZz87SJ41jyx9XKWUtTU4BuEmFUbYQRWAF61/+Qg/Zto/e3P6T11CkVn6eQVctX7x8oM23q0gMeS3LPWppLS9QNkOp0XnIyl/1xNRetHV11SV1mYK1U/+4e9mx6mienH8zePzxN/+6eqtpUyKrlqzn+8ru4aO3o/T/LjziLaY/MpfOSk2t2XZF6UYBuYGFUbaSFFVh71/+QK04dwvhRrVx+6pCqgn2pVi1fvf/nqjkPcdHa0Rwz7z4FaWl4SnEIMDiwLqogPZEO8jeedxAAN36glbvnP03bu/+qqpRJuTLTH5fNe3N/66qlTZP+UNVFMihAS2iBNR3kR3WkvpiN6mipONhXK12yd+AQ9NFNc2NRVRfJENaq3guB84BX3b3pvlc2+0xfYQXWPX/8Nd/87W6++YvdB+w/+JBf017nAJ2mGfikkYXVg/428A3gnpDOFyvNPtNXWIH1sI9+hcNCblvYsgfDNEvKI63ZOxNJE0qAdvcVZjYmjHNJ/TVCYA1bejDMtEfmNlWQbvbORNIoB92Ewqpnbia5XpP0NKlxy0urFyxpdQvQZjYDmAFweIv+LtRSPQaKNJp8r0lmxUdc8tLqBUta3eqg3b3L3Se4+4QOa63XZROnngNFGkWx1yQ94GXDrPklLZwrUi/qypagkWpOw6hnbjbFXpN0+uOK3T18+5+vbLq8tDSusMrsHgDOJrUi7mZgjrsvCOPccdAoeb+4DBSJk1Jek8z0x1VzDo1lXrpUjdSZkOLCquK4NIzzSHXiNFAkLoq9JukA/rPLD+bMb/+cXVvW8Ivdn4tdXrpUxToTugHZWJTiaCK1GCjS6BUhxV6TzPTHCUc4L27fTu9vf8iq5YdGVi9dy16wbkA2FgXoJlKLeuawK0LqHfALvSaZ6Y9X3hhg4/Z+npw+nA/c/WYKJIp6afVkJU2z2UletagICWNK07Bkpj/++Wf7uOLUoakbiae0HNC+O1Zs3D+NqUg9qQcteYVdEZKZ783spUYlM/3RPgQ2fvIQAG78X21V31yNW643X3sk3tSDlpz2f/3/QKpm/cYPtFbdi45iruhCDvvoVxh18R2MeHcnV77/4EE3EjPbt+3VP/G+Sz9Jz0BfSedO53qzf6IKkvlyz1I+M5tkZuvNbIOZfSHPMReb2TozW2tm38nYf7mZ/S74ubzYtdSDlpzCrgiJcwlgsRuJq5av5reLl/H/XnuNNWOHc+bLETU0BC3th6gMrwpm1grMB84BNgMrzWypu6/LOGYscD1wprtvN7O3BvsPB+YAEwAHVgXP3Z7vegrQklPYFSFxLgEsdnO1f3cPL//sUX52eTsf+s4rfOn+f2XZFbfVq3mhGj1r0QHbm249jztHvCei1jSk04EN7r4RwMwWAZOBdRnH/B9gfjrwuvurwf6PAMvcfVvw3GXAJOCBfBdTgJacwq4IieNc0aXKTM1ceuIAn/ru0zyg0YZJdTSQ+R1qM3BG1jHvBjCznwGtwJfc/T/zPPfoQhdTgJa6aNQpTXOlZk7sWsx/f/wvI26ZlKPjoCGcPaakVNpIM+vO2O5y964yLzcEGEtqdPUxwAoze1+Z59h/IqmBmT0b2cMADPQPekyjthpHrtTM9FOcr937IKcUeF7chlzHrT0x9pq7Tyjw+BZgdMb2McG+TJuBZ929F/i9mf2WVMDeQipoZz73qUKNUYCukfTdeo3aamz5UjNjRq9h5iV/mXcYeNz+AMetPQ1sJTDWzI4jFXCnAJdlHfMwcClwl5mNJJXy2Ai8CHzFzEYEx51L6mZiXokL0HGrT5V4y5eaOXniOI6ZPp5pU5tnpXApzt37zGwm8Dip/PJCd19rZnOBbndfGjx2rpmtA/qBz7n7VgAz+zKpIA8wN33DMJ/EBWjNRSBheHNtw+ZbNksKc/fHgMey9s3O+N2BTwc/2c9dCCws9VoaqCIl6d/dw/b/nK0FALLcsWIj/addQOclTbeYvcRA4nrQzWTF4jV0MpUl8+7jYlK9umIqnaxIy2g1P6X/4kcBukbaW9rYw0DN75yXG6QrCbRxm0NDakPpv/hRgK6RevY4VixeA4vH8eAjc1neeSFXzXko53GVBlotoyUSjcQF6CTXg1YSaOM8h4ZIs0tcgE5qLq3SQBvnOTREml1Yi8ZOAm4nVRd4p7vfEsZ5JTyVBtpGnkNDytTSmjvf3NJa/7YIEEKALmX6PYlepYG2UefQKKbR11ospqKKjIF+3SSMmTB60KVMvycRa9ZAW6lmLxtURUZzCGOgSklT6JnZDDPrNrPuN3zwBEIi9VKLtRZFaqFuIwndvcvdJ7j7hA5TTkuiE7elt0TyCSNAlzL9nkgs1GKtRZFaCSMHXcr0e1IH954/m2mPzGXBTfkHqySdygbzS/IYgbiqOkDnm36v6pZJRRSkC0tK2WAlwTapYwTiLJQ66FzT70l07j1/Np2XnMyLd9/Hxff8qqRJlJKi3tUsOwb6uO3PL/GZ4e/g0Jb6jQtTsG0OiRtJWC7N8CXVWNa7lV2tfTzRu5WPH3RU1M2RBqMAXYTqSaVSOwb6eLq3h6euHMYH7+rh3LYj6tqLlsanCftjbMdAH7Pf2EjPQF/UTUmMMBcmWNa7lctPbWP8qFamn9rGE71bQ2ihJIn+nGfJl9LId2wt0xz6elx/5YwwXHDThZw95lA2f2rqoMVj073nuzqHA3B951BOeE69aCmP3ilZslMahVIZpQbyShT7eqzcePjKmS97wU0XMnHrT7j3f+ZeizDde84s55t+ahtPrIv/H1u9t+JDATqGZvZsZMB6uWp86uvxZacO4fpfvUiLv/kBKZYbX7F4DdOmLuXazrO4SlUcJSl1vuz9wbnAQrGr9+3k8e4+vt6974D9Rw0ZiCRAlxN0dd8lPhSgi2hpPyTnG7Ol/RAG9uysyTX3DPQyrH0oN3YOBeDGzoO4e20Lu3bvLes8mTXRd6zYqHK7AsJemODmjuOLHlNK0AyrN6ug25gUoIsYPWsRkHojZ7/By31zl/phG9rKoNFuV5zSyp3d5bb+zZrochaWTaIoRhiWEjRLDaxKS9RPqfPfm9lFwPeAv3D3bjMbA7wArA8Oecbdryl0LQXoOiqnF3PHs7u449kD9w2tcI6pXOmOYvMhN/t8ydlKHWF42sRxnD3mUDbdvqTeTSxIPeT6KHX+ezPrAGYBWZ9iXnT3caVeTwE6S74hsrlWm6jVHAX7+qn5h61YtUKzz5ecrZQRhvtzz2+/sh5NqqvMEY9SUKnz338ZuBX4XDUXU4DOUsrXwfTXyT0DvVy9ff3+/fX8OlnNxDbFqhUqXf27mZVyY7CRZZZ0atKkgnLNf39G5gFm9n5gtLv/h5llB+jjzOxXwOvAF939vwpdTAG6ArX+OlnKB6TcPwSZNwz/dvLFBasVKln9u5mdNnFc1E3IKbNzUMyg91RLKwz07z9P+xD4+SeGc+bCHdzccXzT1Wrbn3fQumppKYeONLPMuz1d7t5V8nXMWoDbgCtyPPwK8A5332pmpwEPm9lJ7v56vvM1179Ck6hVL/ze82fz3vOOh1dWcuN5b86HnFmtEHY1Qy5Jy2/nU8of4nzHtLQfsv8GNhTvHGS/p67evn5/J2Pn8ju4pPUpxo9q5YpxjVGrXUOvufuEAo8Xm/++AzgZeMrMAN4GLDWzC9y9G9gL4O6rzOxF4N1A3tv/CtB1FIevjl9+8OdMe98AozpS18yuVqhHNUPS8tv5lPKHONcxV29ff0BwhvzloMXeW307t7F7zY/44rVvlnRqxGNBBee/d/ceYGR628yeAj4bVHEcCWxz934zeycwFthY6GL6F6ijOJQ7rd63k8ef7ePfnj2wpjpdrVDr+ZKV366N0bMWsenW87hzxHvKet6eZxcN+oPcKCMeo5Bv/nszmwt0u3uhPEonMNfMeoEB4Bp331boegrQCXNzx/F0XnIyx8zLPVd0redLTlJ+uxFqk3f97lnu6Blc0hnViMdGkGv+e3fPeffY3c/O+P1B4MFyrqUAXYFqUhVx+NBGNQy8HvntWqmk9rkRapPfes3dB2xX0guX2lGArkA1gTQuH9oolsZqxPUA41j7HMa9jDjcD5HiqgrQZvZx4EvACcDpwV1KaRD1Xhqr0dYDjGvtcxjftOKSYpHCqu1BrwEuBL4VQlskAisWr6GTqXWZq6Pe6wFWI65DuksRhzSahKOqAO3uLwAE9X7SoFYsXgOLx/HgI3NZ3qnVwBtdXNJoUj3loBOk2ArTUeSlm5nyvFKtogHazH5EajRMthvc/QelXsjMZgAzAA5PcAF8lB/aUpbQqndeupnlSyfM7NmYc5i2UhCSrWikdPcPh3GhYDx7F8CYIe0exjkbSdR5wXJWmK5nXjqJlIKQUiW3K1tnUX8oB60wXWSkWNKD9LWd7yx1ch2Rmqm2zO5jwNeBI4H/MLPV7v6RUFomodEK0+WJa3ldqZT7bh7VVnF8H/h+SG2RGmnkFabr6bSJ41gyfTybPzWVexevibo5FVMeu3mo+5QAla4wnbSVwdNpjRUNHJyluShAJ0ApK0zno6qO8CkFIaVSgK6TqD+U1VSRJP2GYdiUgpBSKUDXSdQfymqrSLJHG96x4sB5xhW0RcKnAC1lSY82nHjSm/v6T7ugZj3rRl0eK+q6d2kOCtBStsHlZ7NrNo9Hoy6PFXXduzSHlqgbIM3h3vNnM3HrT1hw04WhnTM9wf+T0w9m7x+epn93T2jnFmkE6kFXQV9jDxR2xUeSlscSyUUBugqN9DW2XlUkYVV8NPLyWCJhUYBOiHr26DMrPr773jO5+vyJZd/ka8TlsUTCpgAtNXPv+bN5buKxHNxb/k2+RlseK1vUde/SHBSgpWZ2DPRx9w+W8dSVw/jwAys56arPsbb75ZKe20jLY+WSxHsQEj5VcUjNZE5xOvXEAU74w6OcNnFc1M0SqYqZTTKz9Wa2wcy+kOPxa8zseTNbbWY/NbMTMx67PnjeejMrOvOnetBV0NfY/LKnOP3CmW2cdMedrF78ftZqSS1VADUoM2sF5gPnAJuBlWa21N3XZRz2HXf/9+D4C4DbgElBoJ4CnAS8HfiRmb3b3fvzXU8Bugr6IOWXa4rTqSe3MuPSz7P0icNit+5hveeAzq4Aevn2KQzs2cmegd4DlsNSwI6d04EN7r4RwMwWAZOB/QHa3V/POH44kF5BajKwyN33Ar83sw3B+Z7OdzEF6BpKci+p0BSncZshLw4T9A/s2dkwJZuNaN+2bWy6b0kph440s+6M7a5gub60o4HMGymbgTOyT2Jm1wGfBoYCH8p47jNZzz26UGMUoGuokeqkw1ZsitNc9dL//fBn8X27Bh1rQ4fxtr/+auhtbJYJ+iVUr7n7hGpP4u7zgflmdhnwReDySs6jAC2RSQfpB6dezPLOC/nokmsT+wetFEn+RhYjW4DRGdvHBPvyWQR8s8LnKkBLtE7pWsqef39w/3Y6GLe0H8LoWYuialYsJfkbWYysBMaa2XGkgusU4LLMA8xsrLv/Ltj830D696XAd8zsNlI3CccCvyh0sWoXjf0X4HxgH/AicKW776jmnJIsSQ06+SqAJN7cvc/MZgKPA63AQndfa2ZzgW53XwrMNLMPA73AdoL0RnDcElI3FPuA6wpVcED1PehlwPVBo28Frgc+X+U5RSpWah57/43Bt19Zz+btl52SmNmzUSWbDcLdHwMey9o3O+P3WQWeezNwc6nXqnZV7ycyNp8B/qaa8zUb1UmHp9SyPN+3q2iPPA5VG9mUQ5ZcwsxBfwJYnO9BM5sBzAA4vCUZqW996KqTDqrtLW286/brqi7LU9WGNJqikdLMfgS8LcdDN7j7D4JjbiCVU7k/33mCWsIugDFD2j3fcSJpd454z/7fw5jGNB2cVzRocNY3suQpGqDd/cOFHjezK4DzgInursArZSkn6GQvXFvuSMTvvH1cpc2MBX0jS55qqzgmAX8PnOXug+/MiBRRSdBJL1y74KbBq4s/WtJgMZHGUG0y+BvAQcAyMwN4xt2vqbpVUpdBCY088CE9XHzJvPsO2H/U5w5TGkCaRrVVHO8KqyFyoHrUBzd6DXI65ZFpXutRMOKoaBokEjLNBy0iElMK0CIiMZWMguSYaeTcr4jUjwJ0BIrlfmf2bBz0mIgkjwJ0DO0Z6KWl/ZBQqxFy9tpbWhNV8bBjoI/b/vwSnxn+Dg5NyGhWaWx6l8ZUrqk2N916XsUpkEK99swRe81sWe9WdrX28UTvVj5+kCo9JP50k1ASIb2I7Y8vH8YzvT30DPRF3SSRotSDlkRIL2I7flQr009t44l15fWi65ke0U1kSVOAjkAtJ73J9+GmpbXqczeqdO/5rs7hAFzfOZQTnuvh3LYjSg629UyPNPoAIgmPAnQEcvWC0oH16u3rgYwPY0srDKQWXSglgOvDPVi69zyqI5XRG9XRUlYvOh3gn7pyGB+8q7zALlINvctioh438ZJUsZFp9b6dPN7dx9e79x2w/6ghAyUF6GrTIyKVUoBOkKRUa2S7ueP4ip8bRnpEpFJ6h4kUUG16JK50I7IxKECLFFBteqQS9Vg5RfcqGoMCdJPRskjhqiY9Uin1YCVNATomwgqs+nCL1FawktTtQCtwp7vfkvV4J/CvwCnAFHf/XsZj/cDzweZL7n5BoWspQIek2pyeAqtI/JlZKzAfOAfYDKw0s6Xuvi7jsJeAK4DP5jjFbncfV+r1FKBDopyeREk3/ermdGCDu28EMLNFwGRgf4B29z8Ejw1UezEFaKmYgsJg5bwmYb5+5XYQknav4o1tu1NLpBU30sy6M7a73L0rY/to4OWM7c3AGWU0pT04fx9wi7s/XOjgalf1/jKpvx4DwKvAFe7+x2rOKY1D3xoGK+c1ifL1S+of0BK85u4Tanj+Y919i5m9E/ixmT3v7i/mO7ja2ez+xd1PCXIqjwKzqzyfiEicbQFGZ2wfE+wribtvCf67EXgKGF/o+KoCtLu/nrE5HPBqziciEnMrgbFmdpyZDQWmAEtLeaKZjTCzg4LfRwJnkpG7zqXqHLSZ3QxMB3qADxY4bgYwA+DwJhwim7ScnkgSuXufmc0EHidVZrfQ3dea2Vyg292XmtlfAN8HRgDnm9lN7n4ScALwreDmYQupHHR1AdrMfgS8LcdDN7j7D9z9BuAGM7semAnMyfM/1gV0AYwZ0t50PW3l9CRK6iDUj7s/BjyWtW92xu8rSaU+sp/3c+B95VyraIB29w+XeK77STU6Z4CW5qOgMFg5r0mYr586CM2p2iqOse7+u2BzMvCb6pskjUJBYbByXhO9flJMtcngW8zsPaTK7DYB11TfJBERgSoDtLtfFFZDRETkQFrVW0QkphSgRURiSgFaRCSmFKBFRGJKAVpEJKYUoEVEYkoBWkQkphSgRURiSgFaRCSmFKBFRGJKAVpEJKYUoEVEYkoBWkQkphSgRURiSgFaRCSmFKBFRGJKAVpEJKYUoEVEYkoBWkSkDGY2yczWm9kGM/tCjscPMrPFwePPmtmYjMeuD/avN7OPFLuWArSISInMrBWYD/wVcCJwqZmdmHXYVcB2d38XMA+4NXjuicAU4CRgEnBHcL68FKBFREp3OrDB3Te6+z5gETA565jJwN3B798DJpqZBfsXufted/89sCE4X15VrepdqU39e1+7evv6TVFcGxgJvBbRtTPFpR0Qn7aoHYPFpS1RtuPYak+wqX/v41dvXz+yhEPbzaw7Y7vL3bsyto8GXs7Y3gyckXWO/ce4e5+Z9QBHBPufyXru0YUaE0mAdvcjo7gugJl1u/uEqK4ft3ZAfNqidgwWl7bEpR2VcvdJUbehEkpxiIiUbgswOmP7mGBfzmPMbAhwKLC1xOceQAFaRKR0K4GxZnacmQ0lddNvadYxS4HLg9//Bvixu3uwf0pQ5XEcMBb4RaGLRZLiiFhX8UPqIi7tgPi0Re0YLC5tiUs7IhXklGcCjwOtwEJ3X2tmc4Fud18KLADuNbMNwDZSQZzguCXAOqAPuM7d+wtdz1KBXURE4kYpDhGRmFKAFhGJqUQGaDP7spn92sxWm9kTZvb2iNrxL2b2m6At3zezwyJqx8fNbK2ZDZhZ3Uupig2drWM7FprZq2a2Jqo2BO0YbWZPmtm64N9lVoRtaTezX5jZc0FbboqqLUmUyBy0mb3F3V8Pfv8kcKK7XxNBO84ldYe3z8xuBXD3z0fQjhOAAeBbwGfdvbvIU8K8divwW+AcUoX7K4FL3X1dvdqQ0ZZOYCdwj7ufXO/rZ7RjFDDK3X9pZh3AKuCvI3pNDBju7jvNrA34KTDL3Z8p8lQJQSJ70OngHBgORPJXyt2fcPe+YPMZUnWRUbTjBXdfH8W1KW3obF24+wpSd90j5e6vuPsvg9/fAF6gyIizGrbF3X1nsNkW/CSvVxeRRAZoADO72cxeBv4WmB11e4BPAD+MuhERyDV0NpJgFEfBTGjjgWcjbEOrma0GXgWWuXtkbUmapg3QZvYjM1uT42cygLvf4O6jgfuBmVG1IzjmBlJ1kfdH2Q6JFzM7BHgQ+Lusb3115e797j6O1De8080ssvRP0jTtQBV3/3CJh94PPAbMiaIdZnYFcB4w0Wt4Q6CM16Peyh7+mgRBvvdB4H53fyjq9gC4+w4ze5LUVJmR3khNiqbtQRdiZmMzNicDv4moHZOAvwcucPddUbQhBkoZOpsowY25BcAL7n5bxG05Ml1dZGYHk7qZG8nnJYmSWsXxIPAeUpULm4Br3L3uvbZgKOhBpCZSAXgmomqSjwFfB44EdgCr3b3oag8hXv+jwL/y5tDZm+t17ax2PACcTWpqzT8Bc9x9QQTt+ADwX8DzpN6jAP/g7o9F0JZTSM1t3EqqQ7fE3efWux1JlcgALSLSCBKZ4hARaQQK0CIiMaUALSISUwrQIiIxpQAtIhJTCtAiIjGlAC0iElP/H1VSy8jLUVYlAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "_plotting.plot_decision_boundary_2D(features, series_labels, model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "81dca680-329e-4971-a33f-3615ec071741",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
